local brain = require "brains/musha_yamchebrain"

local assets = {
	Asset("ANIM", "anim/musha_chest_ui_0.zip"),
	Asset("ANIM", "anim/musha_chest_ui_1.zip"),
	Asset("ANIM", "anim/musha_chest_ui_2.zip"),
	Asset("ANIM", "anim/musha_yamche_blue.zip"),
	Asset("ANIM", "anim/musha_yamche_base.zip"),
	Asset("ANIM", "anim/musha_yamche_red.zip"),
	Asset("ANIM", "anim/musha_yamche_violet.zip"),
	Asset("ANIM", "anim/musha_yamche_pink.zip"),
	Asset("ANIM", "anim/musha_yamche_green.zip")
}

local function Upgrade(inst, exp)
	if inst.data.currentlevel < inst.maxlevel then
		inst.currentexp = inst.currentexp + exp
	end
end

local function InShadow(inst)
	local x, y, z = inst.Transform:GetWorldPosition()
	local ents = TheSim:FindEntities(x, y, z, 8)
	for k, v in pairs(ents) do
		if
			v.components.health and not v.components.health:IsDead() and v.components.combat and
				v.components.combat.target == inst and
				not (v:HasTag("berrythief") or v:HasTag("prey") or v:HasTag("bird") or v:HasTag("butterfly"))
		 then
			v.components.combat.target = nil
		end
	end
end

local function onignite(inst)
	local danger =
		FindEntity(
		inst,
		3,
		function(target)
			return target:HasTag("monster") or (target.components.combat and target.components.combat.target == inst)
		end
	)
	if danger then
		if inst.components.burnable:IsBurning() and not inst.components.health:IsDead() then
			inst.components.burnable:Extinguish()
			inst.SoundEmitter:PlaySound("dontstarve/common/fireOut")
			inst.components.talker:Say(
				STRINGS.MUSHA_TALK_ORDER_YAMCHE_DANGER .. " \n" .. STRINGS.MUSHA_TALK_ORDER_YAMCHE_CAMPFIRE_OFF
			)
			inst.components.health:DoDelta(30)
		end
	else
		inst.components.health:SetInvincible(true)
		InShadow(inst)
		inst.sg:GoToState("sleep")
		inst.components.follower:SetLeader(nil)
		inst.components.talker:Say(
			STRINGS.MUSHA_TALK_ORDER_YAMCHE_CAMPFIRE_ON .. "\n" .. STRINGS.MUSHA_TALK_ORDER_YAMCHE_FIRE_WARM
		)

		inst.components.locomotor.walkspeed = 0
		if not inst.components.cooker then
			inst:AddComponent("cooker")
		end
	end
end

local function onextinguish(inst)
	inst.components.health:SetInvincible(false)
	if inst.components.sleeper:IsAsleep() then
		inst.components.sleeper:WakeUp()
	end
	inst.components.locomotor.walkspeed = 8
	if inst.components.fueled then
		inst.components.fueled:InitializeFuelLevel(0)
	end
	if inst.components.cooker then
		inst:RemoveComponent("cooker")
	end
end

local function yamche_campfire(inst)
	if not inst.components.burnable then
		inst:AddComponent("burnable")
	end
	inst.components.burnable:AddBurnFX("campfirefire", Vector3(0, .9, 0))

	inst:ListenForEvent("onextinguish", onextinguish)
	inst:ListenForEvent("onignite", onignite)

	inst:AddComponent("fueled")
	inst.components.fueled.maxfuel = TUNING.FIREPIT_FUEL_MAX
	inst.components.fueled.accepting = true
	inst.components.fueled.bonusmult = 2
	inst.components.fueled:SetSections(6)
	inst.components.fueled.ontakefuelfn = function()
		inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
	end
	inst.components.fueled:SetUpdateFn(
		function()
			local fueled = inst.components.fueled

			fueled.rate = TheWorld.state.israining and 1 + TUNING.FIREPIT_RAIN_RATE * TheWorld.state.precipitationrate or 1

			if inst.components.burnable ~= nil then
				inst.components.burnable:SetFXLevel(fueled:GetCurrentSection(), fueled:GetSectionPercent())
			end
		end
	)

	inst.components.fueled:SetSectionCallback(
		function(section)
			if section == 0 then
				inst.components.burnable:Extinguish()
				inst.SoundEmitter:PlaySound("dontstarve/common/fireOut")
			else
				if not inst.components.burnable:IsBurning() then
					inst.components.burnable:Ignite()
				end

				inst.components.burnable:SetFXLevel(section, inst.components.fueled:GetSectionPercent())
			end
		end
	)
end

local function special_yamche(inst) --#TODO: 外观改变
	if inst.type == "red" then
		inst:AddTag("yamche_red")
		inst.AnimState:SetBuild("musha_yamche_red")
		inst.components.health.fire_damage_scale = 0
		inst.Light:SetColour(255, 255, 192)
		inst.Light:SetRadius(5)
		if TheWorld:HasTag("cave") then
			inst.Light:Enable(true)
		else
			inst:WatchWorldState(
				"isnight",
				function(inst, isnight)
					inst.Light:Enable(isnight)
				end
			)
		end
		inst:WatchWorldState(
			"temperature",
			function(inst, temperature)
				if temperature < 10 then
					inst:AddComponent("heater")
					inst.components.heater.heat = 85
				end
			end
		)
		--#TODO: 烤肉
		inst.components.combat:SetDefaultDamage(25)
		inst:ListenForEvent(
			"onattackother",
			function(inst, data)
				if math.random < 0.4 then
					local fx = SpawnPrefab("firesplash_fx")
					fx.Transform:SetScale(1, (0.4 + inst.data.currentlevel * 0.1) * 0.2, 1)
					fx.Transform:SetPosition(data.target:GetPosition():Get())
					if data.target.components.burnable then
						data.target.components.burnable:Ignite()
					end
					data.target.components.health:DoDelta(-10)
				end
			end
		)
	elseif inst.type == "blue" then
		inst:AddTag("yamche_blue")
		inst.AnimState:SetBuild("musha_yamche_blue")
		inst.components.health.fire_damage_scale = 2
		inst.Light:SetColour(0, 183, 1)
		inst.Light:SetRadius(5)
		if TheWorld:HasTag("cave") then
			inst.Light:Enable(true)
		else
			inst:WatchWorldState(
				"isnight",
				function(inst, isnight)
					inst.Light:Enable(isnight)
				end
			)
		end
		inst:WatchWorldState(
			"temperature",
			function(inst, temperature)
				if temperature > 55 then
					inst:AddComponent("heater")
					inst.components.heater.heat = -20
					inst.components.heater:SetThermics(false, true)
				end
			end
		)

		inst.components.combat:SetDefaultDamage(25)
		inst:ListenForEvent(
			"onattackother",
			function(inst, data)
				if math.random() < 0.4 then
					data.target.components.freezable:AddColdness(0.45)
					local fx = SpawnPrefab("icespike_fx_" .. math.random(1, 4))
					fx.Transform:SetScale(1, (0.4 + inst.data.currentlevel * 0.1) * 0.2, 1)
					fx.Transform:SetPosition(data.target:GetPosition():Get())
				end
			end
		)

		local inv = inst.components.container
		for i = 1, inv:GetNumSlots() do
			local item = inv:GetItemInSlot(i)
			if item and item.components.perishable then
				if item.components.perishable.updatetask ~= nil then
					item.components.perishable.updatetask:Cancel()
					item.components.perishable.updatetask = nil
				end
				local dt = 10 + math.random() * FRAMES * 8
				local start_dt = math.random() * 2
				item.components.perishable.updatetask =
					item:DoPeriodicTask(
					dt,
					function(inst, dt)
						local self = inst.components.perishable
						dt = self.start_dt or dt
						self.start_dt = nil
						local old_val = self.perishremainingtime
						local modifier = 1.5
						local delta = dt or (10 + math.random() * FRAMES * 8)
						if self.perishremainingtime then
							self.perishremainingtime = math.min(self.perishtime, self.perishremainingtime - delta * modifier)
							if math.floor(old_val * 100) ~= math.floor(self.perishremainingtime * 100) then
								inst:PushEvent("perishchange", {percent = self:GetPercent()})
							end
						end
					end,
					start_dt,
					dt
				)
			end
		end
	elseif inst.type == "green" then
		inst:AddTag("yamche_green")
		inst.AnimState:SetBuild("musha_yamche_green")
		inst:RemoveComponent("combat")
		inst.components.health.fire_damage_scale = 1.2
		inst.components.hunger.burnratemodifiers:SetModifier(inst, 1.5)
		inst:DoPeriodicTask(
			2,
			function(inst)
				local x, y, z = inst.Transform:GetWorldPosition()
				local ents = TheSim:FindEntities(x, y, z, 20, {"player"})
				for k, v in pairs(ents) do
					if v and v.components.health and not v.components.health:IsDead() and not v:HasTag("playerghost") then
						v.components.health:DoDelta(1)
						inst.SoundEmitter:PlaySound("dontstarve/creatures/chester/raise")
						inst.SoundEmitter:PlaySound("dontstarve/creatures/chester/pop")
						SpawnPrefab("sparks").Transform:SetPosition(inst:GetPosition():Get())
						SpawnPrefab("sparks").Transform:SetPosition(v.Transform:GetPosition():Get())
						SpawnPrefab("green_leaves").Transform:SetPosition(v.Transform:GetWorldPosition())
						SpawnPrefab("green_leaves").Transform:SetPosition(inst.Transform:GetWorldPosition())
					end
				end
			end
		)
	elseif inst.type == "pink" then
		inst:AddTag("yamche_pink")
		inst.AnimState:SetBuild("musha_yamche_pink")
		yamche_campfire(inst)
		inst.components.combat:SetDefaultDamage(40)
		inst:ListenForEvent(
			"onattackother",
			function(inst, data)
				local target = data.target
				local walkspeed = target.components.locomotor.walkspeed
				local runspeed = target.components.locomotor.runspeed
				if target.poison_debuff_task == nil then
					target.components.locomotor.walkspeed = walkspeed * 0.8
					target.components.locomotor.runspeed = runspeed * 0.8
					SpawnPrefab("musha_spin_fx").entity:AddFollower():FollowSymbol(target.GUID, "body", 0, -200, 0.5)
					target.poison_debuff_task =
						target:DoTaskInTime(
						3,
						function(target)
							target.components.locomotor.walkspeed = walkspeed
							target.components.locomotor.runspeed = runspeed
						end
					)
				else
					target.poison_debuff_task:Cancel()
					target.poison_debuff_task =
						target:DoTaskInTime(
						3,
						function(target)
							target.components.locomotor.walkspeed = walkspeed
							target.components.locomotor.runspeed = runspeed
						end
					)
				end
			end
		)
	elseif inst.type == "violet" then
		inst:AddTag("yamche_violet")
		inst.AnimState:SetBuild("musha_yamche_violet")
		inst.components.health.fire_damage_scale = 0
		yamche_campfire(inst)
		inst.components.combat:SetDefaultDamage(35)
		inst:ListenForEvent(
			"onattackother",
			function(inst, data)
				if math.random < 0.35 then
					SpawnPrefab("musha_lightning_blue"):Transform(data.target:GetWorldPosition():Get())
					data.attacker.components.health:DoDelta(-10)
					if inst.components.health:IsHurt() then
						inst.components.health:DoDelta(9)
					elseif inst.components.follower.leader.components.health:IsHurt() then
						inst.components.follower.leader.components.health:DoDelta(9)
					end
				end
			end
		)
	end
end

local function GetYamcheSanityAura(inst, observer)
	if inst.components.hunger:GetPercent() < .5 then
		return TUNING.SANITYAURA_TINY
	elseif inst.components.hunger:GetPercent() >= .5 then
		return TUNING.SANITYAURA_SMALL_TINY
	end
end

local function OnGetItemFromPlayer(inst, item)
	if inst.type then
		if inst.components.sleeper:IsAsleep() then
			inst.components.sleeper:WakeUp()
			if inst.components.burnable:IsBurning() then
				inst.components.burnable:Extinguish()
				inst.SoundEmitter:PlaySound("dontstarve/common/fireOut")
			end
		end

		if item.prefab == "musha_cristal" then
			inst.type = nil
			inst.AnimState:SetBuild("musha_yamche_base")
			return true
		end
		if item.components.edible then
			return inst.components.eater:CanEat(item) and inst.components.hunger:GetPercent() <= 0.9
		end
	else
		if
			string.find(item.prefab, "monstermeat") or item.prefab == "petals_evil" or item.prefab == "nightmarefuel" or
				item.prefab == "purplegem"
		 then
			inst.type = "violet"
		elseif string.find(item.prefab, "cooked") or item.prefab == "redgem" then
			inst.type = "red"
		elseif string.find(item.prefab, "ice") or string.find(item.prefab, "watermelon") or item.prefab == "bluegem" then
			inst.type = "blue"
		elseif string.find(item.prefab, "seeds") or item.prefab == "greengem" then
			inst.type = "green"
		elseif item.prefab == "tentaclespots" or item.prefab == "spidergland" then
			inst.type = "pink"
		else
			return false
		end
		musha_print("Choose_type", item.prefab, inst.type)
		return true
	end
end

local function OnRefuseItem(inst, item)
	inst.sg:GoToState("refuse")
end

local function OnEat(inst, food)
	inst.components.combat:SetTarget(nil)
	inst.sg:GoToState("eat")
	inst.sg:GoToState("graze")
	--inst.components.hunger:DoDelta(5)
	local food_value =
		food.components.edible and
		3 * food.components.edible.hungervalue + 2 * food.components.edible.sanityvalue +
			5 * food.components.edible.healthvalue or
		40
	Upgrade(inst, food_value)

	if inst.components.hunger:GetPercent() >= 1 then
		local fx = SpawnPrefab("poopcloud")
		fx.Transform:SetScale(
			0.3 + inst.data.currentlevel / inst.maxlevel,
			0.3 + inst.data.currentlevel / inst.maxlevel,
			0.3 + inst.data.currentlevel / inst.maxlevel
		)
		fx.Transform:SetPosition(inst:GetPosition():Get())
		local poo = SpawnPrefab("poop")
		fx.Transform:SetScale(
			0.3 + inst.data.currentlevel / inst.maxlevel,
			0.3 + inst.data.currentlevel / inst.maxlevel,
			0.3 + inst.data.currentlevel / inst.maxlevel
		)
		poo.Transform:SetPosition(inst:GetPosition():Get())
	end

	inst.components.health:DoDelta(food.components.edible.hungervalue * .2, nil, food.prefab)
end

local function yamche()
	local inst = CreateEntity()
	inst.entity:AddLight()
	inst.entity:AddSoundEmitter()
	inst.entity:AddNetwork()
	inst.entity:AddTransform()
	inst.entity:AddAnimState()
	inst.entity:AddMiniMapEntity()
	inst.entity:AddDynamicShadow()
	inst.MiniMapEntity:SetIcon("musha_yamche.tex")
	inst.MiniMapEntity:SetCanUseCache(false)
	inst.MiniMapEntity:SetDrawOverFogOfWar(true)

	inst.Transform:SetFourFaced()

	inst.DynamicShadow:SetSize(.8, .5)
	inst.Light:SetRadius(1.8)
	inst.Light:SetFalloff(.8)
	inst.Light:SetIntensity(.5)

	inst.AnimState:SetBank("smallbird")
	inst.AnimState:SetBuild("musha_yamche_base")
	inst.AnimState:PlayAnimation("idle", true)

	MakeCharacterPhysics(inst, 10, .5)

	inst.Physics:SetDontRemoveOnSleep(true)
	inst.Physics:SetCollisionGroup(COLLISION.CHARACTERS)
	inst.Physics:ClearCollisionMask()
	inst.Physics:CollidesWith(COLLISION.WORLD)
	inst.Physics:CollidesWith(COLLISION.OBSTACLES)
	inst.Physics:CollidesWith(COLLISION.CHARACTERS)
	inst.Physics:SetCylinder(.5, 1)

	inst:AddTag("musha_yamche")
	inst:AddTag("musha_follower")
	inst:AddTag("notraptrigger")
	--inst:AddTag("flying")
	--inst:AddTag("maprevealer")

	inst:AddComponent("talker")
	inst.components.talker.fontsize = 22
	inst.components.talker.colour = Vector3(1, 0.85, 0.75, 1)

	inst.entity:SetPristine()

	if not TheWorld.ismastersim then
		return inst
	end

	inst:AddComponent("maprevealer")

	inst:AddComponent("follower")
	inst.components.follower:KeepLeaderOnAttacked()
	inst.components.follower.keepdeadleader = true

	inst:AddComponent("waterproofer")
	inst.components.waterproofer.effectiveness = 0

	inst:AddComponent("trader")
	inst.components.trader:SetAcceptTest(OnGetItemFromPlayer)
	inst.components.trader.onrefuse = OnRefuseItem

	inst:AddComponent("eater")
	inst.components.eater:SetDiet({FOODGROUP.OMNI}, {FOODGROUP.OMNI})
	inst.components.eater.strongstomach = true

	inst:SetStateGraph("SGmusha_yamche")

	inst.action = "stay"

	inst:AddComponent("knownlocations")

	inst:AddComponent("locomotor")
	inst.components.locomotor.walkspeed = 6
	inst.components.locomotor.runspeed = 8

	inst.data = {}
	inst.savedata = {
		currentexp = 0,
		currentlevel = 0,
		levelexp = 0
	}
	inst.maxlevel = 6
	setmetatable(
		inst.data,
		{
			__index = inst.savedata,
			__newindex = function(t, key, value)
				inst.savedata[key] = value
				if key == "currentexp" then
					local currentexp_new, currentlevel_new = inst.data.currentexp, inst.data.currentlevel
					while currentexp_new >= inst.data.levelexp and inst.data.currentlevel < inst.maxlevel do
						currentexp_new = currentexp_new - inst.data.levelexp
						currentlevel_new = currentlevel_new + 1
						inst.data.levelexp = currentlevel_new * 30
					end

					if currentlevel_new ~= inst.data.currentlevel then
						inst.yamche_info()
					end
					inst.savedata.currentlevel = currentlevel_new
					inst.savedata.currentexp = currentexp_new
				elseif key == "currentlevel" then
					inst.data.levelexp = inst.data.currentlevel * 30
					local health_percent = inst.components.health:GetPercent()
					inst.components.health.maxhealth = 150 + inst.data.currentlevel * 35
					inst.components.health:SetPercent(health_percent)
					if not inst.type == "green" then
						if inst.data.currentlevel >= 3 then
							if not inst.components.container then
								inst:AddComponent("container")
							end
							if inst.data.currentlevel < 4 then
								inst.components.container:WidgetSetup("musha_chest_2")
							elseif inst.data.currentlevel < 5 then
								inst.components.container:WidgetSetup("musha_chest_3")
							else
								inst.components.container:WidgetSetup("musha_chest_4")
							end
						end
					else
						if inst.data.currentlevel >= 3 then
							if not inst.components.container then
								inst:AddComponent("container")
							end
							inst.components.container:WidgetSetup("chest_yamche_green_3")
						end
					end
				elseif key == "type" then
					inst.components.eater:SetOnEatFn(OnEat)
					special_yamche(inst)
				end
			end
		}
	)

	inst:SetBrain(brain)

	inst:AddComponent("named")
	inst.components.named.possiblenames = STRINGS.PHOENIXS
	inst.components.named:PickNewName()

	inst:AddComponent("sanityaura")
	inst.components.sanityaura.aurafn = GetYamcheSanityAura

	inst:AddComponent("sleeper")
	inst.components.sleeper:SetResistance(5)
	inst.components.sleeper.sleeptestfn = function(inst)
		return not inst.components.follower.leader and DefaultSleepTest(inst)
	end

	inst:AddComponent("health")
	inst.components.health.canmurder = false
	inst.components.health:SetAbsorptionAmount(0.5)
	--inst.components.health:SetAbsorptionAmountFromPlayer(1)

	inst:AddComponent("hunger")
	inst.components.hunger:SetMax(350)
	inst.components.hunger:SetRate(TUNING.LAVAE_HUNGER_RATE)

	inst:AddComponent("playerprox")
	inst.components.playerprox:SetDist(6, 6)
	inst.components.playerprox:SetOnPlayerNear(
		function(inst)
			inst.components.locomotor.walkspeed = 2
		end
	)
	inst.components.playerprox:SetOnPlayerFar(
		function(inst)
			inst.components.locomotor.walkspeed = 7
		end
	)

	--inst.sg:GoToState("idle_peep")

	inst:AddComponent("combat") --#TODO: PVP
	inst.components.combat.playerdamagepercent = 0

	inst:AddComponent("inspectable")
	inst.components.inspectable:RecordViews()

	inst:ListenForEvent(
		"onkill",
		function(inst, data)
			Upgrade(inst, data.victim.components.combat.defaultdamage * 0.5)
		end
	)

	inst:ListenForEvent(
		"onopen",
		function(inst, data)
			if data.doer:HasTag("monkey") then
				inst.components.talker:Say(RandomChoice(STRINGS.MUSHA_TALK_THIEF))
				inst.components.container:Close()
			end
		end
	)

	inst.OnSave = function(inst, data)
		data.savedata = inst.savedata
	end
	inst.OnLoad = function(inst, data)
		if data ~= nil then
			inst.data.currentexp = data.savedata.currentexp
			inst.data.currentlevel = data.savedata.currentlevel
			inst.data.type = data.savedata.type
		end
	end

	inst.order = function(inst, commander, action)
		musha_print("yamche receive order", action)
		if inst.ownerid == commander.userid then
			if not inst:IsNear(commander, 20) then
				commander.components.talker:Say(STRINGS.MUSHA_TALK_ORDER_YAMCHE_LOST)
				return
			end
			if action == "follow" then
				inst.components.talker:Say(STRINGS.YAMCHE_FOLLOW .. "\n" .. STRINGS.YAMCHE_HUNGER_RATE .. "[1x]")
				inst.components.follower:SetLeader(commander)
				inst.components.hunger.burnratemodifiers:SetModifier(inst)
				return
			elseif action == "stay" then
				inst.components.talker:Say(STRINGS.YAMCHE_REST .. "\n" .. STRINGS.YAMCHE_HUNGER_RATE .. "[0]")
				inst.components.hunger.burnratemodifiers:SetModifier(inst, 0)
				inst.components.follower:SetLeader(nil)
				return
			end
			inst.action = action
			if action == "fight" then
				inst.components.talker:Say(STRINGS.YAMCHE_DEFFENSE .. "\n" .. STRINGS.YAMCHE_HUNGER_RATE .. "[2.5x]")
				inst.components.hunger.burnratemodifiers:SetModifier(inst, 2.5)
			elseif action == "avoid" then
				if inst.type == "green" then
					inst.components.talker:Say(STRINGS.YAMCHE_FOLLOW .. "\n" .. STRINGS.YAMCHE_HUNGER_RATE .. "[1.25x]")
					inst.components.hunger.burnratemodifiers:SetModifier(inst, 1.25)
				else
					inst.components.talker:Say(STRINGS.YAMCHE_FOLLOW .. "\n" .. STRINGS.YAMCHE_HUNGER_RATE .. "[1x]")
					inst.components.hunger.burnratemodifiers:SetModifier(inst)
				end
			elseif action == "pick" then
				inst.components.talker:Say(STRINGS.YAMCHE_STUFF .. "\n" .. STRINGS.YAMCHE_HUNGER_RATE .. "[3x]")
				inst.components.hunger.burnratemodifiers:SetModifier(inst, 3)
			end
		end
	end
	inst.yamche_info = function()
		inst.components.talker:Say(
			inst.components.named.name ..
				STRINGS.MUSHA_LEVEL_LEVEL ..
					inst.data.currentlevel .. STRINGS.MUSHA_LEVEL_EXP .. inst.data.currentexp / inst.data.levelexp
		)
	end

	inst:DoTaskInTime(
		0,
		function(inst)
			if inst.icon == nil then
				inst.icon = SpawnPrefab("globalmapicon")
				inst.icon.MiniMapEntity:SetIsFogRevealer(true)
				inst.icon:TrackEntity(inst)
			end
		end
	)

	return inst
end

return Prefab("musha_yamche", yamche, assets)
--DebugSpawn("musha_yamche")
